#ifndef CLCOMMAP_H
#define CLCOMMAP_H

#include <map>
#include <string>
#include <QMutex>
#include "CLComLibrarys_global.h"
//CLCOMLIBRARYS_EXPORT

using namespace std;

#define CTASKMAP_ERRORID		-3
#define CTASKMAP_NOTFOUND		-1
#define CTASKMAP_EXIST			-2
#define CTASKMAP_FALSE			0
#define CTASKMAP_OK				1
#define CTASKMAP_IT_MAXCOUNT	100

#define TASKMAP_DEL_SET_NULL(p) {if(p){delete p; p = NULL;}}
#define TASKMAP_DEL_SET_NULLS(p) {if(p){delete[] p; p = NULL;}}

template<typename TypeKey, typename TypeData>
class CLCOMLIBRARYS_EXPORT CLComMap
{
public:
    CLComMap();
    ~CLComMap();
public:
    void Clone( CLComMap& other, bool bDestroyMyself);
    void Clone(CLComMap& other);
public:
    int GetSize();
    int Add2Map(const TypeData& data, const TypeKey& keyvalue);
    int GetData(TypeData& data, const TypeKey& keyvalue);
    int GetDataAndErase(TypeData& data, const TypeKey& keyvalue);
    int UpdateData(const TypeData& data, const TypeKey& keyvalue);
    int UpdateData(const TypeData& data, const TypeKey& keyvalue, bool bcreate);

    int EraseData(TypeKey& keyvalue);
    int EraseDataEx(TypeKey keyvalue);

    int EraseDataAndReleaseHeap(TypeKey& keyvalue);//需要释放
    int DataIsExist(const TypeKey& keyvalue);
    int GetDataFirstAndErase(TypeData& data);


    int GetNextData(TypeData& data, int nUID);
    int GetFirstData(TypeData& data, int nUID);

    int GetNextData(TypeData& data, TypeKey& keyvalue, int nUID);
    int GetFirstData(TypeData& data, TypeKey& keyvalue, int nUID);

    int GetFirstDataOnly(TypeData& data, TypeKey& keyvalue);

    int GetLastData(TypeData& data);
    void DestroyMap();//释放map，如果map中有new的空间则可能需要这个函数
    void ClearMap();

    void SetAddFinish(bool bAddFinish);
    bool BAddFinish();
public:
    int WantEnumElements();
    void FinishedEnumElements(int nUID);
private:
    map<TypeKey, TypeData> _taskMap;
    typename map<TypeKey, TypeData>::iterator _its[CTASKMAP_IT_MAXCOUNT];
    map<int, bool> m_mapITUseFlag;

    bool m_bAddFinish;
private:
    QMutex cs;
};

template<typename TypeKey, typename TypeData>
void CLComMap<TypeKey, TypeData>::Clone( CLComMap& other, bool bDestroyMyself)
{
    if (bDestroyMyself)
    {
        DestroyMap();
    }
    ClearMap();

    cs.lock();

    int nId = other.WantEnumElements();

    TypeData tdata;
    TypeKey tkey;
    if (CTASKMAP_OK == other.GetFirstData(tdata, tkey, nId))
    {
        do
        {
            _taskMap[tkey] = tdata;

        } while (CTASKMAP_OK == other.GetNextData(tdata, tkey, nId));
    }
    other.FinishedEnumElements(nId);

    cs.unlock();
}
template<typename TypeKey, typename TypeData>
void CLComMap<TypeKey, TypeData>::Clone(CLComMap& other)
{
    ClearMap();

    cs.lock();

    int nId = other.WantEnumElements();

    TypeData tdata;
    TypeKey tkey;
    if (CTASKMAP_OK == other.GetFirstData(tdata, tkey, nId))
    {
        do
        {
            _taskMap[tkey] = tdata;

        } while (CTASKMAP_OK == other.GetNextData(tdata, tkey, nId));
    }
    other.FinishedEnumElements(nId);

    cs.unlock();
}

template<typename TypeKey, typename TypeData>
void CLComMap<TypeKey,TypeData>::ClearMap()
{
    cs.lock();
    _taskMap.clear();

    for (int i = 0; i < CTASKMAP_IT_MAXCOUNT; ++i)
    {
        _its[i] = _taskMap.begin();
    }
    cs.unlock();
}
template<typename TypeKey, typename TypeData>
void CLComMap<TypeKey,TypeData>::DestroyMap()
{
    cs.lock();
    auto it = _taskMap.begin();
    for ( ; it != _taskMap.end(); ++it )
    {
        TASKMAP_DEL_SET_NULL(it->second);
    }
    _taskMap.clear();

    for (int i = 0; i < CTASKMAP_IT_MAXCOUNT; ++i)
    {
        _its[i] = _taskMap.begin();
    }
    cs.unlock();
}

template<typename TypeKey, typename TypeData>
CLComMap<TypeKey,TypeData>::CLComMap()
{
    m_bAddFinish = false;
    for (int i = 0; i < CTASKMAP_IT_MAXCOUNT; ++i)
    {
        m_mapITUseFlag[i] = false;
    }
}

template<typename TypeKey,typename TypeData>
CLComMap<TypeKey,TypeData>::~CLComMap()
{

}
template<typename TypeKey, typename TypeData>
int CLComMap<TypeKey, TypeData>::GetSize()
{
    cs.lock();
    int size = (int)_taskMap.size();
    cs.unlock();

    return size;
}
template<typename TypeKey, typename TypeData>
int CLComMap<TypeKey, TypeData>::Add2Map(const TypeData& data, const TypeKey& keyvalue)
{
    cs.lock();
    if (_taskMap.end() != _taskMap.find(keyvalue))
    {
        cs.unlock();
        return CTASKMAP_EXIST;
    }
    _taskMap.insert(pair<TypeKey, TypeData>(keyvalue, data));

    for (int i = 0; i < CTASKMAP_IT_MAXCOUNT; ++i)
    {
        _its[i] = _taskMap.begin();
    }
    cs.unlock();

    return CTASKMAP_OK;
}
template<typename TypeKey, typename TypeData>
int CLComMap<TypeKey, TypeData>::GetData(TypeData& data, const TypeKey& keyvalue)
{
    cs.lock();
    auto it = _taskMap.find(keyvalue);
    if ( it != _taskMap.end() )
    {
        data = it->second;
    }
    else
    {
        cs.unlock();
        return CTASKMAP_NOTFOUND;
    }
    cs.unlock();
    return CTASKMAP_OK;
}
template<typename TypeKey, typename TypeData>
int CLComMap<TypeKey, TypeData>::GetDataFirstAndErase(TypeData& data)
{
    cs.lock();
    auto it = _taskMap.begin();
    if ( it != _taskMap.end() )
    {
        data = it->second;
        _taskMap.erase(it);
    }
    else
    {
        cs.unlock();
        return CTASKMAP_NOTFOUND;
    }
    for (int i = 0; i < CTASKMAP_IT_MAXCOUNT; ++i)
    {
        _its[i] = _taskMap.begin();
    }
    cs.unlock();
    return CTASKMAP_OK;
}
template<typename TypeKey, typename TypeData>
int CLComMap<TypeKey, TypeData>::DataIsExist(const TypeKey& keyvalue)
{
    cs.lock();
    auto it = _taskMap.find(keyvalue);
    if ( it != _taskMap.end() )
    {
        cs.unlock();
        return CTASKMAP_OK;
    }
    else
    {
        cs.unlock();
        return CTASKMAP_NOTFOUND;
    }
}

template<typename TypeKey, typename TypeData>
int CLComMap<TypeKey, TypeData>::GetDataAndErase(TypeData& data, const TypeKey& keyvalue)
{
    cs.lock();
    auto it = _taskMap.find(keyvalue);
    if ( it != _taskMap.end() )
    {
        data = it->second;
        _taskMap.erase(it);
    }
    else
    {
        cs.unlock();
        return CTASKMAP_NOTFOUND;
    }
    for (int i = 0; i < CTASKMAP_IT_MAXCOUNT; ++i)
    {
        _its[i] = _taskMap.begin();
    }
    cs.unlock();
    return CTASKMAP_OK;
}
template<typename TypeKey, typename TypeData>
int CLComMap<TypeKey, TypeData>::UpdateData(const TypeData& data, const TypeKey& keyvalue, bool bcreate)
{
    cs.lock();
    auto it = _taskMap.find(keyvalue);
    if (it != _taskMap.end())
    {
        it->second = data;
    }
    else if (bcreate)
    {
        _taskMap[keyvalue] = data;
        cs.unlock();
    }
    else
    {
        cs.unlock();
        return CTASKMAP_NOTFOUND;
    }
    cs.unlock();
    return CTASKMAP_OK;
}
template<typename TypeKey, typename TypeData>
int CLComMap<TypeKey, TypeData>::UpdateData(const TypeData& data, const TypeKey& keyvalue)
{
    cs.lock();
    auto it = _taskMap.find(keyvalue);
    if ( it != _taskMap.end() )
    {
        it->second = data;
    }
    else
    {
        cs.unlock();
        return CTASKMAP_NOTFOUND;
    }
    cs.unlock();
    return CTASKMAP_OK;
}
template<typename TypeKey, typename TypeData>
int CLComMap<TypeKey, TypeData>::EraseData(TypeKey& keyvalue)
{
    cs.lock();
    auto it = _taskMap.find(keyvalue);
    if ( it != _taskMap.end() )
    {
        _taskMap.erase(it);
    }
    else
    {
        cs.unlock();
        return CTASKMAP_NOTFOUND;
    }
    for (int i = 0; i < CTASKMAP_IT_MAXCOUNT; ++i)
    {
        _its[i] = _taskMap.begin();
    }
    cs.unlock();
    return CTASKMAP_OK;
}
template<typename TypeKey, typename TypeData>
int CLComMap<TypeKey, TypeData>::EraseDataEx(TypeKey keyvalue)
{
    cs.lock();
    auto it = _taskMap.find(keyvalue);
    if (it != _taskMap.end())
    {
        _taskMap.erase(it);
    }
    else
    {
        cs.unlock();
        return CTASKMAP_NOTFOUND;
    }
    for (int i = 0; i < CTASKMAP_IT_MAXCOUNT; ++i)
    {
        _its[i] = _taskMap.begin();
    }
    cs.unlock();
    return CTASKMAP_OK;
}
template<typename TypeKey, typename TypeData>
int CLComMap<TypeKey, TypeData>::EraseDataAndReleaseHeap(TypeKey& keyvalue)
{
    cs.lock();
    auto it = _taskMap.find(keyvalue);
    if ( it != _taskMap.end() )
    {
        TASKMAP_DEL_SET_NULL(it->second);
        _taskMap.erase(it);
    }
    else
    {
        cs.unlock();
        return CTASKMAP_NOTFOUND;
    }
    for (int i = 0; i < CTASKMAP_IT_MAXCOUNT; ++i)
    {
        _its[i] = _taskMap.begin();
    }
    cs.unlock();
    return CTASKMAP_OK;
}

template<typename TypeKey, typename TypeData>
int CLComMap<TypeKey, TypeData>::WantEnumElements()
{
    int nID = CTASKMAP_NOTFOUND;

    cs.lock();
    for (int i = 0; i < CTASKMAP_IT_MAXCOUNT; ++i)
    {
        if (!m_mapITUseFlag[i])
        {
            m_mapITUseFlag[i] = true;
            nID = i;
            break;
        }
    }
    cs.unlock();

    return nID;
}

template<typename TypeKey, typename TypeData>
void CLComMap<TypeKey, TypeData>::FinishedEnumElements(int nUID)
{
    if (nUID == CTASKMAP_NOTFOUND)
    {
        return;
    }
    cs.lock();

    m_mapITUseFlag[nUID] = false;

    cs.unlock();
}

template<typename TypeKey, typename TypeData>
int CLComMap<TypeKey, TypeData>::GetNextData(TypeData& data, int nUID)
{
    if (nUID == CTASKMAP_NOTFOUND)
    {
        return CTASKMAP_ERRORID;
    }
    cs.lock();
    if (_its[nUID] == _taskMap.end())
    {
        cs.unlock();
        return CTASKMAP_NOTFOUND;
    }
    ++_its[nUID];
    if (_its[nUID] != _taskMap.end())
    {
        data = _its[nUID]->second;
        cs.unlock();
        return CTASKMAP_OK;
    }
    else
    {
        cs.unlock();
        return CTASKMAP_NOTFOUND;
    }
}
template<typename TypeKey, typename TypeData>
int CLComMap<TypeKey, TypeData>::GetFirstData(TypeData& data, int nUID)
{
    if (nUID == CTASKMAP_NOTFOUND)
    {
        return CTASKMAP_ERRORID;
    }
    cs.lock();
    _its[nUID] = _taskMap.begin();
    if (_its[nUID] != _taskMap.end())
    {
        data = _its[nUID]->second;
        cs.unlock();
        return CTASKMAP_OK;
    }
    else
    {
        cs.unlock();
        return CTASKMAP_NOTFOUND;
    }
}
template<typename TypeKey, typename TypeData>
int CLComMap<TypeKey, TypeData>::GetNextData(TypeData& data, TypeKey& keyvalue, int nUID)
{
    if (nUID == CTASKMAP_NOTFOUND)
    {
        return CTASKMAP_ERRORID;
    }
    cs.lock();
    if (_its[nUID] == _taskMap.end())
    {
        cs.unlock();
        return CTASKMAP_NOTFOUND;
    }
    ++_its[nUID];
    if (_its[nUID] != _taskMap.end())
    {
        data = _its[nUID]->second;
        keyvalue = _its[nUID]->first;
        cs.unlock();
        return CTASKMAP_OK;
    }
    else
    {
        cs.unlock();
        return CTASKMAP_NOTFOUND;
    }
}
template<typename TypeKey, typename TypeData>
int CLComMap<TypeKey, TypeData>::GetFirstData(TypeData& data, TypeKey& keyvalue, int nUID)
{
    if (nUID == CTASKMAP_NOTFOUND)
    {
        return CTASKMAP_ERRORID;
    }
    cs.lock();
    _its[nUID] = _taskMap.begin();
    if (_its[nUID] != _taskMap.end())
    {
        data = _its[nUID]->second;
        keyvalue = _its[nUID]->first;
        cs.unlock();
        return CTASKMAP_OK;
    }
    else
    {
        cs.unlock();
        return CTASKMAP_NOTFOUND;
    }
}
template<typename TypeKey, typename TypeData>
int CLComMap<TypeKey, TypeData>::GetFirstDataOnly(TypeData& data, TypeKey& keyvalue)
{
    cs.lock();
    auto it = _taskMap.begin();
    if (it != _taskMap.end())
    {
        data = it->second;
        keyvalue = it->first;
        cs.unlock();
        return CTASKMAP_OK;
    }
    else
    {
        cs.unlock();
        return CTASKMAP_NOTFOUND;
    }
}
template<typename TypeKey, typename TypeData>
int CLComMap<TypeKey, TypeData>::GetLastData(TypeData& data)
{
    cs.lock();
    if (0 == _taskMap.size())
    {
        cs.unlock();
        return CTASKMAP_NOTFOUND;
    }
    auto it = _taskMap.end();
    --it;
    if (it != _taskMap.end())
    {
        data = it->second;
        cs.unlock();
        return CTASKMAP_OK;
    }
    else
    {
        cs.unlock();
        return CTASKMAP_NOTFOUND;
    }
    cs.unlock();
}
template<typename TypeKey, typename TypeData>
void CLComMap<TypeKey, TypeData>::SetAddFinish(bool bAddFinish)
{
    cs.lock();
    m_bAddFinish = bAddFinish;
    cs.unlock();
}
template<typename TypeKey, typename TypeData>
bool CLComMap<TypeKey, TypeData>::BAddFinish()
{
    return m_bAddFinish;
}
#endif // CLCOMMAP_H
